package me.zhengjie.log.utils;

import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ObjectUtils;

import javax.servlet.http.HttpServletRequest;
import java.net.*;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Optional;
import java.util.regex.Pattern;

/**
 * 获取本机IP 地址
 */

@Configuration
@RequiredArgsConstructor
public class IpUtil {


    // IPv4地址的正则表达式
    private static final String IPV4_REGEX =
            "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";

    // 编译正则表达式模式
    private static final Pattern IPV4_PATTERN = Pattern.compile(IPV4_REGEX);


    /*
     * 获取本机所有网卡信息   得到所有IP信息
     * @return Inet4Address>
     */
    public List<Inet4Address> getLocalIp4AddressFromNetworkInterface() throws SocketException {
        List<Inet4Address> addresses = new ArrayList<>(1);

        // 所有网络接口信息
        Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
        if (ObjectUtils.isEmpty(networkInterfaces)) {
            return addresses;
        }
        while (networkInterfaces.hasMoreElements()) {
            NetworkInterface networkInterface = networkInterfaces.nextElement();
            //滤回环网卡、点对点网卡、非活动网卡、虚拟网卡并要求网卡名字是eth或ens开头
            if (!isValidInterface(networkInterface)) {
                continue;
            }

            // 所有网络接口的IP地址信息
            Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
            while (inetAddresses.hasMoreElements()) {
                InetAddress inetAddress = inetAddresses.nextElement();
                // 判断是否是IPv4，并且内网地址并过滤回环地址.
                if (isValidAddress(inetAddress)) {
                    addresses.add((Inet4Address) inetAddress);
                }
            }
        }
        return addresses;
    }

    /**
     * 过滤回环网卡、点对点网卡、非活动网卡、虚拟网卡并要求网卡名字是eth或ens开头
     *
     * @param ni 网卡
     * @return 如果满足要求则true，否则false
     */
    private boolean isValidInterface(NetworkInterface ni) throws SocketException {
        return !ni.isLoopback() && !ni.isPointToPoint() && ni.isUp() && !ni.isVirtual()
                && (ni.getName().startsWith("eth") || ni.getName().startsWith("ens"));
    }

    /**
     * 判断是否是IPv4，并且内网地址并过滤回环地址.
     */
    private boolean isValidAddress(InetAddress address) {
        return address instanceof Inet4Address && address.isSiteLocalAddress() && !address.isLoopbackAddress();
    }

    /*
     * 通过Socket 唯一确定一个IP
     * 当有多个网卡的时候，使用这种方式一般都可以得到想要的IP。甚至不要求外网地址8.8.8.8是可连通的
     * @return Inet4Address>
     */
    private Optional<Inet4Address> getIpBySocket() throws SocketException {
        try (final DatagramSocket socket = new DatagramSocket()) {
            socket.connect(InetAddress.getByName("8.8.8.8"), 10002);
            if (socket.getLocalAddress() instanceof Inet4Address) {
                return Optional.of((Inet4Address) socket.getLocalAddress());
            }
        } catch (UnknownHostException networkInterfaces) {
            throw new RuntimeException(networkInterfaces);
        }
        return Optional.empty();
    }

    /**
     * 获取Nginx转发后的真实客户端IP
     *
     * @param request HTTP请求对象
     * @return 原始客户端IP（如192.10.88.100）
     */
    public String getRealIp(HttpServletRequest request) {
        // 1. 优先读取X-Real-IP（Nginx直接设置的真实IP）
        String ip = request.getHeader("X-Real-IP");
        if (isValidIp(ip)) {
            return ip;
        }

        // 2. 读取X-Forwarded-For（可能包含多个IP，取第一个）
        ip = request.getHeader("X-Forwarded-For");
        if (isValidIp(ip)) {
            // X-Forwarded-For格式：客户端IP, 代理1IP, 代理2IP...
            int index = ip.indexOf(',');
            if (index != -1) {
                return ip.substring(0, index).trim(); // 取第一个IP
            } else {
                return ip.trim();
            }
        }

        // 3. 如果以上都没有，使用默认方法（可能是Nginx服务器IP）
        return request.getRemoteAddr();
    }

    /**
     * 验证IP是否有效（非null、非empty、非unknown）
     */
    private static boolean isValidIp(String ip) {
        return ip != null && !ip.isEmpty() && !"unknown".equalsIgnoreCase(ip);
    }

    /*
     * 获取本地IPv4地址
     * @return Inet4Address>
     */
    public Optional<Inet4Address> getLocalIp4Address() throws SocketException {
        final List<Inet4Address> inet4Addresses = getLocalIp4AddressFromNetworkInterface();
        if (inet4Addresses.size() != 1) {
            final Optional<Inet4Address> ipBySocketOpt = getIpBySocket();
            if (ipBySocketOpt.isPresent()) {
                return ipBySocketOpt;
            } else {
                return inet4Addresses.isEmpty() ? Optional.empty() : Optional.of(inet4Addresses.get(0));
            }
        }
        return Optional.of(inet4Addresses.get(0));
    }

    public String getRemoteIp() throws SocketException {
        Optional<Inet4Address> localIp4Address = this.getLocalIp4Address();
        if (!localIp4Address.isPresent()) {
            return null;
        }
        Inet4Address inet4Address = localIp4Address.get();
        return inet4Address.toString().replaceAll("/", "");
    }

    public String getRemoteIp(HttpServletRequest request) {
        if (request == null) {
            try {
                return this.getRemoteIp();
            } catch (Exception e) {
                throw new RuntimeException("获取用户地址异常");
            }
        }
        String clientIp = request.getHeader("X-Real-IP");
        if (clientIp == null || clientIp.isEmpty()) {
            String xff = request.getHeader("X-Forwarded-For");
            if (xff != null && !xff.isEmpty()) {
                // X-Forwarded-For: 客户端IP, 代理1IP, ...
                clientIp = xff.split(",")[0].trim(); // 取第一个 IP
            } else {
                clientIp = request.getRemoteAddr(); // 最后兜底，可能是 Nginx 的 IP
            }
        }
        return clientIp;
    }

    /**
     * 判断IP地址是否为本地回环地址（127.0.0.0/8网段）
     */
    public boolean isLocalLoopback(String ipAddress) {
        try {
            InetAddress addr = InetAddress.getByName(ipAddress);
            return addr.isLoopbackAddress();
        } catch (UnknownHostException e) {
            return false;
        }
    }

    /**
     * 判断IP地址是否为局域网IP（私有IP地址）
     */
    public boolean isLanIp(String ipAddress) {
        try {
            InetAddress addr = InetAddress.getByName(ipAddress);
            byte[] bytes = addr.getAddress();

            // 检查是否为IPv4地址
            if (bytes.length != 4) {
                return false; // 非IPv4不视为局域网IP
            }

            // 转换为无符号整数
            int ip = ((bytes[0] & 0xFF) << 24) |
                    ((bytes[1] & 0xFF) << 16) |
                    ((bytes[2] & 0xFF) << 8) |
                    (bytes[3] & 0xFF);

            // 检查是否属于私有IP网段
            return isInRange(ip, 0x0A000000, 0x0AFFFFFF) || // 10.0.0.0 - 10.255.255.255
                    isInRange(ip, 0xAC100000, 0xAC1FFFFF) || // 172.16.0.0 - 172.31.255.255
                    isInRange(ip, 0xC0A80000, 0xC0A8FFFF);   // 192.168.0.0 - 192.168.255.255
        } catch (UnknownHostException e) {
            return false;
        }
    }

    /**
     * 辅助方法：判断IP是否在指定范围内（整数表示）
     */
    private boolean isInRange(int ip, int start, int end) {
        return ip >= start && ip <= end;
    }

    /**
     * 局域网IP/本地回环地址
     *
     * @param ipAddress IP地址
     * @return boolean
     */
    public boolean getISLocalAddr(String ipAddress) {
        return isLanIp(ipAddress) || isLocalLoopback(ipAddress);
    }


}


